<template>
  <div class="map-wrapper">
    <div id="container"></div>
    <div class="map-utils-layers">
      <Checkbox
        v-model="layerDisplay.satellite"
        @on-change="routeMapLayer('satellite')"
      >卫星图</Checkbox>
      <Checkbox
        v-model="layerDisplay.roadnet"
        @on-change="routeMapLayer('roadnet')"
      >路网图</Checkbox>
      <Checkbox
        v-model="layerDisplay.traffic"
        @on-change="routeMapLayer('traffic')"
      >实时路况</Checkbox>
      <Checkbox
        v-model="layerDisplay.building"
        @on-change="routeMapLayer('building')"
      >建筑楼块</Checkbox>
      <input
        type="text"
        id="map-search"
        class="map-utils-textbox"
        placeholder="输入关键字快速定位区域"
      />
    </div>
    <div
      id="mask"
      v-show="maskOn"
    ></div>
  </div>
</template>

<script>
import { busEventEmit, busEventHandle } from "@/teleport/bus";
import jsonDownloader from "@/libs/exportJSON";
import config from "@/config/global";

export default {
  name: "",
  data() {
    return {
      map: null,
      maskOn: false,
      layers: {
        satellite: null,
        roadnet: null,
        traffic: null,
        building: null,
      },
      layerDisplay: {
        satellite: false,
        roadnet: false,
        traffic: false,
        building: false,
      },
      mouseTool: null,
      counter: {
        poi: 0,
        path: 0,
        range: 0,
        effect: 0,
      },
      mouseDrawMode: null,
      polyEditor: null,
      eventHandler: {
        click: null,
        pathedit: null,
        rangeedit: null,
        searchedSelect: null,
      },
      placeSearch: null,
    };
  },
  watch: {
    $route: {
      handler(v) {
        switch (v.path) {
          case "/create-poi":
            this.mouseDrawMode = "poi";
            break;
          case "/create-path":
            this.mouseDrawMode = "path";
            break;
          case "/create-range":
            this.mouseDrawMode = "range";
            break;
          case "/create-effect":
            this.mouseDrawMode = "effect";
            break;
        }
        this.registerMapEvent();
      },
      immediate: true,
      deep: true,
    },
  },
  mounted() {
    this.initAMap();
    this.listenDrawRequestEvent();
    this.listenCoverageDataCompleteEvent();
    this.listenCoverageRemoveEvent();
  },
  methods: {
    initAMap() {
      this.map = new AMap.Map("container", {
        mapStyle: "amap://styles/macaron",
        zoom: 12,
        // viewMode: "3D",
        // resizeEnable: true,
        // rotateEnable: true,
        // pitchEnable: true,
        // buildingAnimation:true,
        // expandZoomRange:true
      });
      store.drawHistory = new Array();
      AMap.plugin(
        [
          "AMap.MouseTool",
          "AMap.ToolBar",
          "AMap.Driving",
          "AMap.Autocomplete",
          "AMap.PlaceSearch",
          "AMap.PolyEditor",
          "AMap.CircleEditor",
          "AMap.RangingTool",
        ],
        (e) => {
          this.initAMapMouseTool();
          this.listenPOIDrawEvent();
        }
      );
      this.initAvailableLayer();
      this.initAMapSearchService();
    },
    listenDrawRequestEvent() {
      const $this = this;
      busEventHandle("poi-draw-request", () => {
        $this.mouseTool.marker({
          draggable: true,
          cursor: "move",
          raiseOnDrag: true,
        });
      });
      busEventHandle("poi-draw-cancel", () => {
        $this.mouseTool.close();
      });
      busEventHandle("path-draw-request", () => {
        $this.mouseTool.polyline();
      });
      busEventHandle("path-draw-cancel", () => {
        $this.mouseTool.close();
      });
      busEventHandle("range-draw-request", () => {
        $this.mouseTool.polygon();
      });
      busEventHandle("range-draw-cancel", () => {
        $this.mouseTool.close();
      });
      busEventHandle("effect-draw-request", () => {
        $this.mouseTool.circle();
      });
      busEventHandle("effect-draw-cancel", () => {
        $this.mouseTool.close();
      });
    },
    listenCoverageDataCompleteEvent() {
      const $this = this;
      busEventHandle("poi-data-complete", (msg) => {
        const marker = store.latestDrawn;
        marker.setExtData(msg);
        marker.setIcon(`${config.imageUrl}${msg.iconName}.png`);
        marker.setAnchor("top-left");
        marker.setOffset(
          new AMap.Pixel(config.imageOffset[0], config.imageOffset[1])
        );
        marker.setLabel({
          offset: new AMap.Pixel(-10, 10),
          content: `<div class="marker-label">${msg.title}</div>`,
          direction: "right",
        });
        $this.polyEditor = null;
        this.maskOn = false;
      });
      busEventHandle("poi-data-mutanted", (msg) => {
        const marker = store.drawHistory.find((e) => {
          return e.getExtData().id === msg.id;
        });
        marker.setExtData(msg);
        marker.setIcon(`${config.imageUrl}${msg.iconName}.png`);
        marker.setAnchor("top-left");
        marker.setOffset(
          new AMap.Pixel(config.imageOffset[0], config.imageOffset[1])
        );
        marker.setLabel({
          offset: new AMap.Pixel(10, 10),
          content: `<div class="marker-label">${msg.title}</div>`,
          direction: "right",
        });
        $this.polyEditor = null;
        this.maskOn = false;
      });
      busEventHandle("path-data-complete", (msg) => {
        const polyline = store.latestDrawn;
        polyline.setExtData(msg);
        polyline.setOptions({
          strokeColor: msg.color,
          strokeOpacity: 1,
          strokeWeight: 10,
          strokeStyle: "dashed",
          showDir: true,
        });
        $this.polyEditor = null;
        this.maskOn = false;
      });
      busEventHandle("path-data-mutanted", (msg) => {
        const polyline = store.drawHistory.find((e) => {
          return e.getExtData().id === msg.id;
        });
        $this.polyEditor.close();
        //$this.polyEditor = null;
        polyline.setExtData(msg);
        polyline.setOptions({
          strokeColor: msg.color,
          strokeOpacity: 1,
          strokeWeight: 10,
          strokeStyle: "dashed",
          showDir: true,
        });
        polyline.w.clickable = true;
        this.maskOn = false;
      });
      busEventHandle("range-data-complete", (msg) => {
        const polygon = store.latestDrawn;
        polygon.setExtData(msg);
        polygon.setOptions({
          strokeColor: msg.color,
          strokeOpacity: 1,
          strokeWeight: 10,
          strokeStyle: "dashed",
          fillColor: msg.color,
          fillOpacity: 0.5,
        });
        //$this.polyEditor = null;
        this.maskOn = false;
      });
      busEventHandle("range-data-mutanted", (msg) => {
        const polygon = store.drawHistory.find((e) => {
          return e.getExtData().id === msg.id;
        });
        $this.polyEditor.close();
        //$this.polyEditor = null;
        polygon.setExtData(msg);
        polygon.setOptions({
          strokeColor: msg.color,
          strokeOpacity: 1,
          strokeWeight: 10,
          strokeStyle: "dashed",
          fillColor: msg.color,
          fillOpacity: 0.5,
        });
        polygon.w.clickable = true;
        this.maskOn = false;
      });
      busEventHandle("effect-data-complete", (msg) => {
        const circle = store.latestDrawn;
        circle.setExtData(msg);
        circle.setOptions({
          strokeColor: "#3d8c00",
          strokeOpacity: 1,
          strokeWeight: 10,
          strokeStyle: "dashed",
          fillColor: "#3d8c00",
          fillOpacity: 0.2,
        });
        //$this.polyEditor = null;
        this.maskOn = false;
      });
      busEventHandle("effect-data-mutanted", (msg) => {
        const circle = store.drawHistory.find((e) => {
          return e.getExtData().id === msg.id;
        });
        $this.polyEditor.close();
        //$this.polyEditor = null;
        circle.setExtData(msg);
        circle.setOptions({
          strokeColor: "#3d8c00",
          strokeOpacity: 1,
          strokeWeight: 10,
          strokeStyle: "dashed",
          fillColor: "#3d8c00",
          fillOpacity: 0.2,
        });
        circle.w.clickable = true;
        this.maskOn = false;
      });
    },
    listenCoverageRemoveEvent() {
      busEventHandle("delete-poi", (msg) => {
        const marker = store.drawHistory.find((e) => {
          return e.getExtData().id === msg;
        });
        marker.setMap(null);
        store.drawHistory = store.drawHistory.filter((e) => {
          return e.id !== msg;
        });
      });
      busEventHandle("delete-path", (msg) => {
        const path = store.drawHistory.find((e) => {
          return e.getExtData().id === msg;
        });
        store.drawHistory = store.drawHistory.filter((e) => {
          return e.getExtData().id !== msg;
        });
        path.setMap(null);
      });
      busEventHandle("delete-range", (msg) => {
        const range = store.drawHistory.find((e) => {
          return e.getExtData().id === msg;
        });
        store.drawHistory = store.drawHistory.filter((e) => {
          return e.getExtData().id !== msg;
        });
        range.setMap(null);
      });
      busEventHandle("delete-effect", (msg) => {
        const effect = store.drawHistory.find((e) => {
          return e.getExtData().id === msg;
        });
        store.drawHistory = store.drawHistory.filter((e) => {
          return e.getExtData().id !== msg;
        });
        effect.setMap(null);
      });
    },
    initAvailableLayer() {
      this.layers.satellite = new AMap.TileLayer.Satellite({
        zooms: [1, 30],
        opacity: 1,
        visibile: true,
        zIndex: 4,
      });
      this.layers.roadnet = new AMap.TileLayer.RoadNet({
        zooms: [1, 30],
        opacity: 1,
        visibile: true,
        zIndex: 8,
      });
      this.layers.traffic = new AMap.TileLayer.Traffic({
        zooms: [1, 30],
        zIndex: 10,
      });
      this.layers.building = new AMap.Buildings({
        zooms: [1, 30],
        zIndex: 9,
      });
    },
    initAMapMouseTool() {
      this.mouseTool = new AMap.MouseTool(this.map);
      const $this = this;
      this.mouseTool.on("draw", (e) => {
        //遮住地图区域和左侧工具栏，防止表单完善数据前继续插入
        switch ($this.mouseDrawMode) {
          case "poi":
            $this.emitPOIDrawnEvent(e);
            break;
          case "path":
            $this.emitPathDrawnEvent(e);
            break;
          case "range":
            $this.emitRangeDrawnEvent(e);
            break;
          case "effect":
            $this.emitEffectDrawnEvent(e);
            break;
        }
      });
    },
    emitPOIDrawnEvent(e) {
      const $this = this;
      $this.maskOn = true;
      store.drawHistory.push(e.obj);
      store.latestDrawn = e.obj;
      $this.listenClickEvent(e.obj);
      $this.listenDragEvent(e.obj);
      busEventEmit("poi-drawn", {
        poiCount: $this.counter.poi,
        coord: `${e.obj.getPosition().lng},${e.obj.getPosition().lat}`,
      });
      $this.counter.poi++;
    },
    emitPathDrawnEvent(e) {
      const $this = this;
      $this.maskOn = true;
      if (e.obj.CLASS_NAME === "AMap.Polyline") {
        store.drawHistory.push(e.obj);
        $this.listenClickEvent(e.obj);
        store.latestDrawn = e.obj;
        busEventEmit("path-drawn", {
          pathCount: $this.counter.path,
          points: e.obj.getPath().map((o) => {
            return {
              coord: `${o.lng},${o.lat}`,
              coord_z: 1,
            };
          }),
        });
        $this.counter.path++;
      }
    },
    emitRangeDrawnEvent(e) {
      const $this = this;
      $this.maskOn = true;
      if (e.obj.CLASS_NAME === "AMap.Polygon") {
        store.drawHistory.push(e.obj);
        $this.listenClickEvent(e.obj);
        store.latestDrawn = e.obj;
        busEventEmit("range-drawn", {
          rangeCount: $this.counter.range,
          points: e.obj.getPath().map((o) => {
            return {
              coord: `${o.lng},${o.lat}`,
              coord_z: 1,
            };
          }),
        });
        $this.counter.range++;
      }
    },
    emitEffectDrawnEvent(e) {
      const $this = this;
      $this.maskOn = true;
      if (e.obj.CLASS_NAME === "AMap.Circle") {
        store.drawHistory.push(e.obj);
        $this.listenClickEvent(e.obj);
        store.latestDrawn = e.obj;
        busEventEmit("effect-drawn", {
          effectCount: $this.counter.effect,
          coord: `${e.obj.getCenter().lng},${e.obj.getCenter().lat}`,
          radius: e.obj.getRadius(),
        });
        $this.counter.effect++;
      }
    },
    initAMapSearchService() {
      let autoOptions = {
        input: "map-search",
      };
      let autoService = new AMap.Autocomplete(autoOptions);
      const select = (e) => {
        this.placeSearch.setCity(e.poi.adcode);
        this.placeSearch.search(e.poi.name); //关键字查询查询
      };
      this.placeSearch = new AMap.PlaceSearch({
        map: this.map,
      });
      this.placeSearch.on("markerClick", this.eventHandler.click);
      AMap.event.addListener(autoService, "select", select); //注册监听，当选中某条记录时会触发
    },
    routeMapLayer(name) {
      if (this.layerDisplay[name]) {
        this.layers[name].setMap(this.map);
      } else {
        this.layers[name].setMap(null);
      }
    },
    updateCoverageAppearance(coverage) {
      let thisOne = coverage;
      let others = null;
      switch (coverage.CLASS_NAME) {
        case "AMap.Marker":
          thisOne = coverage;
          thisOne.setIcon(
            `${config.imageUrl}${
              coverage.getExtData().iconName
            }-clicked.png`
          );
          others = store.drawHistory.filter((e) => {
            return (
              e.getExtData().id !== coverage.getExtData().id &&
              e.CLASS_NAME === "AMap.Marker"
            );
          });
          if (others) {
            others.forEach((o) => {
              o.setIcon(
                `${config.imageUrl}${coverage.getExtData().iconName}.png`
              );
            });
          }
          break;
        case "AMap.Polyline":
          thisOne = coverage;
          thisOne.setOptions({
            strokeStyle: "solid",
          });
          others = store.drawHistory.filter((e) => {
            return (
              e.getExtData().id !== coverage.getExtData().id &&
              e.CLASS_NAME === "AMap.Polyline"
            );
          });
          if (others) {
            others.forEach((o) => {
              o.setOptions({
                strokeStyle: "dashed",
              });
            });
          }
          break;
        case "AMap.Polygon":
          thisOne = coverage;
          thisOne.setOptions({
            strokeStyle: "solid",
          });
          others = store.drawHistory.filter((e) => {
            return (
              e.getExtData().id !== coverage.getExtData().id &&
              e.CLASS_NAME === "AMap.Polygon"
            );
          });
          if (others) {
            others.forEach((o) => {
              o.setOptions({
                strokeStyle: "dashed",
              });
            });
          }
          break;
        case "AMap.Circle":
          thisOne = coverage;
          thisOne.setOptions({
            strokeStyle: "solid",
          });
          others = store.drawHistory.filter((e) => {
            return (
              e.getExtData().id !== coverage.getExtData().id &&
              e.CLASS_NAME === "AMap.Circle"
            );
          });
          if (others) {
            others.forEach((o) => {
              o.setOptions({
                strokeStyle: "dashed",
              });
            });
          }
          break;
      }
    },
    registerMapEvent() {
      const $this = this;
      this.eventHandler.click = (event) => {
        let targetCoverage = event.target;
        console.dir(targetCoverage);
        switch (targetCoverage.CLASS_NAME) {
          case "AMap.Marker":
            if ($this.mouseDrawMode === "poi") {
              busEventEmit("poi-edit", {
                id: targetCoverage.getExtData().id,
                coord: `${targetCoverage.getPosition().lng},${
                  targetCoverage.getPosition().lat
                }`,
              });
              $this.updateCoverageAppearance(targetCoverage);
            }
            break;
          case "AMap.Polyline":
            if ($this.mouseDrawMode === "path") {
              let id = targetCoverage.getExtData().id;
              //if(targetCoverage)
              if (targetCoverage.w.clickable) {
                $this.polyEditor = new AMap.PolyEditor(
                  $this.map,
                  targetCoverage
                );
                $this.polyEditor.open();
                $this.listenPolyEditEvent(targetCoverage, "path");
                targetCoverage.w.clickable = false;
                busEventEmit("path-edit", {
                  ...targetCoverage.getExtData(),
                  points: targetCoverage.getPath().map((o) => {
                    return {
                      coord: `${o.lng},${o.lat}`,
                      coord_z: 1,
                    };
                  }),
                });
                $this.updateCoverageAppearance(targetCoverage);
              }
            }
            break;
          case "AMap.Polygon":
            if ($this.mouseDrawMode === "range") {
              let id = targetCoverage.getExtData().id;
              $this.polyEditor = new AMap.PolyEditor($this.map, targetCoverage);
              $this.polyEditor.open();
              $this.listenPolyEditEvent(targetCoverage, "range");
              targetCoverage.w.clickable = false;
              busEventEmit("range-edit", {
                ...targetCoverage.getExtData(),
                points: targetCoverage.getPath().map((o) => {
                  return {
                    coord: `${o.lng},${o.lat}`,
                    coord_z: 1,
                  };
                }),
              });
              $this.updateCoverageAppearance(targetCoverage);
            }
            break;
          case "AMap.Circle":
            if ($this.mouseDrawMode === "effect") {
              let id = targetCoverage.getExtData().id;
              $this.polyEditor = new AMap.CircleEditor(
                $this.map,
                targetCoverage
              );
              $this.polyEditor.open();
              $this.listenPolyEditEvent(targetCoverage, "effect");
              targetCoverage.w.clickable = false;
              busEventEmit("effect-edit", {
                ...targetCoverage.getExtData(),
                coord: `${targetCoverage.getCenter().lng},${
                  targetCoverage.getCenter().lat
                }`,
                radius: targetCoverage.getRadius(),
              });
              $this.updateCoverageAppearance(targetCoverage);
            }
            break;
        }
      };
      this.eventHandler.searchedSelect = (event) => {
        debugger;
      };
      if (store.drawHistory) {
        if (store.drawHistory.length > 0) {
          this.dispatchClickEvent();
          this.restoreClickEvent();
        }
      }
    },
    listenClickEvent(coverage) {
      coverage.on("click", this.eventHandler.click);
    },
    dispatchClickEvent() {
      const eventHandler = this.eventHandler.click;
      switch (this.mouseDrawMode) {
        case "poi":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME !== "AMap.Marker";
            })
            .forEach((o) => {
              o.off("click", eventHandler);
            });
          this.mouseTool.close();
          break;
        case "path":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME !== "AMap.Polyline";
            })
            .forEach((o) => {
              o.off("click", eventHandler);
            });
          this.mouseTool.close();
          break;
        case "range":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME !== "AMap.Polygon";
            })
            .forEach((o) => {
              o.off("click", eventHandler);
            });
          this.mouseTool.close();
          break;
        case "effect":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME !== "AMap.Circle";
            })
            .forEach((o) => {
              o.off("click", eventHandler);
            });
          this.mouseTool.close();
          break;
      }
    },
    restoreClickEvent() {
      const eventHandler = this.eventHandler.click;
      const $this = this;
      switch (this.mouseDrawMode) {
        case "poi":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME === "AMap.Marker";
            })
            .forEach((o) => {
              $this.listenClickEvent(o);
            });
          break;
        case "path":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME === "AMap.Polyline";
            })
            .forEach((o) => {
              $this.listenClickEvent(o);
            });
          break;
        case "range":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME === "AMap.Polygon";
            })
            .forEach((o) => {
              $this.listenClickEvent(o);
            });
          break;
        case "effect":
          store.drawHistory
            .filter((e) => {
              return e.CLASS_NAME === "AMap.Circle";
            })
            .forEach((o) => {
              $this.listenClickEvent(o);
            });
          break;
      }
    },
    listenPolyEditEvent(targetCoverage, type) {
      this.eventHandler.pathedit = (event) => {
        switch (type) {
          case "path":
            busEventEmit("path-edit", {
              ...targetCoverage.getExtData(),
              points: targetCoverage.getPath().map((o) => {
                return {
                  coord: `${o.lng},${o.lat}`,
                  coord_z: 1,
                };
              }),
            });
            break;
          case "range":
            busEventEmit("range-edit", {
              ...targetCoverage.getExtData(),
              points: targetCoverage.getPath().map((o) => {
                return {
                  coord: `${o.lng},${o.lat}`,
                  coord_z: 1,
                };
              }),
            });
            break;
          case "effect":
            busEventEmit("effect-edit", {
              ...targetCoverage.getExtData(),
              coord: `${targetCoverage.getCenter().lng},${
                targetCoverage.getCenter().lat
              }`,
              radius: targetCoverage.getRadius(),
            });
            break;
        }
      };
      if (type === "effect") {
        this.polyEditor.on("move", this.eventHandler.pathedit);
        this.polyEditor.on("adjust", this.eventHandler.pathedit);
      } else {
        this.polyEditor.on("addnode", this.eventHandler.pathedit);
        this.polyEditor.on("adjust", this.eventHandler.pathedit);
        this.polyEditor.on("removenode", this.eventHandler.pathedit);
      }
    },
    listenDragEvent(coverage) {
      coverage.on("dragend", (event) => {
        let targetCoverage = event.target;
        this.updateCoverageAppearance(coverage);
        switch (targetCoverage.CLASS_NAME) {
          case "AMap.Marker":
            busEventEmit("poi-edit", {
              id: targetCoverage.getExtData().id,
              coord: `${targetCoverage.getPosition().lng},${
                targetCoverage.getPosition().lat
              }`,
            });
            break;
          case "AMap.Polyline":
            busEventEmit("path-edit", {
              id: targetCoverage.getExtData().id,
              points: targetCoverage.getPath().map((o) => {
                return {
                  coord: `${o.lng},${o.lat}`,
                  coord_z: 1,
                };
              }),
            });
            break;
          case "AMap.Polygon":
            busEventEmit("range-edit", {
              id: targetCoverage.getExtData().id,
              points: targetCoverage.getPath().map((o) => {
                return {
                  coord: `${o.lng},${o.lat}`,
                  coord_z: 1,
                };
              }),
            });
            break;
        }
      });
    },
  },
};
</script>

<style scoped>
#mask {
  position: fixed;
  background: #00000044;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 99;
}
#container {
  width: 100vw;
  height: 100vh;
  position: fixed;
  z-index: 0;
}
.map-utils-layers {
  display: flex;
  flex-flow: row nowrap;
  align-items: center;
  position: fixed;
  left: 64px;
  bottom: 16px;
  background: #fff;
  padding: 16px;
  border-radius: 6px;
  box-shadow: 0 3px 3px #00000055;
}
.map-utils-textbox {
  border-radius: 5px;
  border: 1px #d1d4df solid;
  width: 275px;
  padding: 5px;
  font-size: 12px;
  margin: 0 12px;
}
.marker-label {
  background: #000000aa;
  color: #fff;
  border: 1px #000 solid;
  border-radius: 2px;
}
</style>